package com.xyy.saas.payment.adapter.channel.fm.config;

import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigChangeListener;
import com.ctrip.framework.apollo.ConfigService;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.xyy.saas.payment.common.constants.ApolloConstants;
import com.xyy.saas.payment.common.constants.ChannelConstants;
import com.xyy.saas.payment.enums.AmountTypeEnum;
import com.xyy.saas.payment.enums.BusinessType;
import com.xyy.saas.payment.enums.CostType;
import com.xyy.saas.payment.exception.PaymentException;
import com.xyy.saas.payment.manage.cores.bo.SyncFMPayReportConfigBO;
import com.xyy.saas.payment.pojo.vo.DictEntity;
import com.xyy.saas.payment.util.ApolloUtil;
import com.xyy.saas.payment.util.JSONUtils;
import com.xyy.saas.payment.util.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;

import java.util.*;

@Slf4j
@Component
@DependsOn({"apolloUtil"})
public class BankConfigManager implements InitializingBean {

    private Map<String, ChinaBankBusinessConfig> chinaBankMap = new HashMap<>();
    private Map<String, FuminBankBusinessConfig> fuminBankMap = new HashMap<>();
    private Map<String, FuminBankPayConfig> fuminBankPayConfigMap = new HashMap<>();
    private Map<String, List<ProfitSharingAccountConfig>> profitSharingAccountConfig = new HashMap<>();
    private List<SyncFMPayReportConfigBO> accountList = new ArrayList<>();

    public List<SyncFMPayReportConfigBO> getFuminAccountConfig() {
        return Collections.unmodifiableList(accountList);
    }

    public String getProfitSharingAccount(String businessOrderType, AmountTypeEnum amountType) throws PaymentException
    {
        if(profitSharingAccountConfig.isEmpty()) {
            throw new PaymentException("Profit sharing account not configured with Apollo");
        }

        List<ProfitSharingAccountConfig> items = profitSharingAccountConfig.get(businessOrderType);

        if(CollectionUtils.isEmpty(items)) {
            throw new PaymentException("Profit sharing account not configured with " + businessOrderType);
        }

        for(ProfitSharingAccountConfig item : items) {
            String account = item.matchAccount(amountType);

            if(!StringUtils.isEmpty(account)) {
                return account;
            }
        }

        throw new PaymentException("Profit sharing account not fount with businessOrderType=" +
                businessOrderType + ", amountType=" + amountType.name());
    }

    /**
     * 初始化配置
     */
    private void initConfig() {
        Map<String, String> configs = JSONUtils.parse2Map(ApolloUtil.getProperty(ApolloConstants.BANK_BUSINESS_ORDER_CONFIG_NEW), String.class, String.class);
        Map<String, ChinaBankBusinessConfig> tmpChinaBankMap = new HashMap<>(16);
        Map<String, FuminBankBusinessConfig> tmpFuminBankMap = new HashMap<>(16);
        for(String bankType : configs.keySet()) {
            switch (bankType) {
                case ChannelConstants.CHANNEL_CHINA_BANK_NAME:
                    castVal2ChinaBankConfig(configs.get(bankType), tmpChinaBankMap);
                    continue;
                case ChannelConstants.CHANNEL_FUMIN_BANK_NAME:
                    castVal2FuminBankConfig(configs.get(bankType), tmpFuminBankMap);
                    continue;
                default:
            }
        }
        if(!tmpChinaBankMap.isEmpty()) {
            chinaBankMap = tmpChinaBankMap;
        }
        if(!tmpFuminBankMap.isEmpty()) {
            fuminBankMap = tmpFuminBankMap;
        }
    }

    private void initFuminPayConfig() {
        Map<String, FuminBankPayConfig> tmpfuminBankPayConfigMap = new HashMap<>(16);
        String val = ApolloUtil.getProperty(ApolloConstants.BANK_FUMIN_PAY_CONFIG);
        List<FuminBankPayConfig> list = JSONUtils.parse2List(val, FuminBankPayConfig.class);
        for(FuminBankPayConfig c : list) {
            tmpfuminBankPayConfigMap.put(c.getBusinessOrderType(), c);
        }

        fuminBankPayConfigMap = tmpfuminBankPayConfigMap;
    }

    private void initProfitSharingAccountConfig() {
        Map<String, String> configs = JSONUtils.parse2Map(ApolloUtil.getProperty(ApolloConstants.PROFIT_SHARING_ACCOUNT_CONFIG), String.class, String.class);

        if(configs == null || configs.isEmpty()) {
            return;
        }

        Map<String, List<ProfitSharingAccountConfig>> map = new HashMap<>(16);

        configs.entrySet().forEach(config -> {
            map.put(config.getKey(), JSONUtils.parse2List(config.getValue(), ProfitSharingAccountConfig.class));
        });

        if(!map.isEmpty()) {
            profitSharingAccountConfig = map;
        }
    }

    private void initFuminAccountConfig() {
        List<SyncFMPayReportConfigBO> accountList = JSONUtils.parse2List(ApolloUtil.getProperty(ApolloConstants.FUMIN_ACCOUNT_CONFIG), SyncFMPayReportConfigBO.class);
        if(accountList == null || accountList.isEmpty()) {
            return;
        }
        this.accountList = accountList;

        // 更新Bean
        List<DictEntity> list = SpringUtils.getBean("fuminBusinessTypeMap", List.class);
        if(CollectionUtils.isNotEmpty(list)) {
            // 清空
            for (DictEntity dictEntity : list) {
                if(CollectionUtils.isNotEmpty(dictEntity.getChildrenList())) {
                    dictEntity.getChildrenList().clear();
                }
            }

            for (SyncFMPayReportConfigBO bo : accountList) {
                for (DictEntity dictEntity : list) {
                    if (dictEntity.getValue().equals(bo.getBusinessType())) {
                        DictEntity dict = new DictEntity();
                        dict.setKey(bo.getAccountType());
                        dict.setLabel(bo.getDesc());
                        dict.setValue(bo.getAccountType());
                        if (org.springframework.util.CollectionUtils.isEmpty(dictEntity.getChildrenList())) {
                            List<DictEntity> tmp = new ArrayList<>();
                            tmp.add(dict);
                            dictEntity.setChildrenList(tmp);
                        } else {
                            dictEntity.getChildrenList().add(dict);
                        }
                    }
                }
            }
        }
    }

    public String getPrivateKeyByMch(String mch) {
        return ApolloUtil.getProperty(ChannelConstants.CHANNEL_CHINA_BANK_NAME + "_privatekey_" + mch);
    }

    public String getPublicKeyByMch(String mch) {
        return ApolloUtil.getProperty(ChannelConstants.CHANNEL_CHINA_BANK_NAME + "_publickey_" + mch);
    }

    public String getChinaBankAccessNo(String businessOrderType) {
       return chinaBankMap.get(businessOrderType).getBankAccessNo();
    }

    public String getChinaBankMch(String businessOrderType) {
       return chinaBankMap.get(businessOrderType).getBankMch();
    }

    public String getFuminBankMch(String businessOrderType) {
        return fuminBankMap.get(businessOrderType).getBankMch();
    }

    public boolean isFuminBankAggregatePay(String businessOrderType) {
        if(StringUtils.isBlank(businessOrderType)) {
            return false;
        }

        return fuminBankPayConfigMap.containsKey(businessOrderType);
    }

    public String checkRoute(String businessType) {
        /**
         * NOTICE:由于业务从中行->富民，富民优先级高于中行
         */
        if(fuminBankMap.keySet().contains(businessType)) {
            return ChannelConstants.CHANNEL_FUMIN_BANK_NAME;
        }
        if(chinaBankMap.keySet().contains(businessType)) {
            return ChannelConstants.CHANNEL_CHINA_BANK_NAME;
        }
        return null;
    }

    private void castVal2ChinaBankConfig(String val, Map<String, ChinaBankBusinessConfig> tmpChinaBankMap) {
        List<ChinaBankBusinessConfig> list = JSONUtils.parse2List(val, ChinaBankBusinessConfig.class);
        for(ChinaBankBusinessConfig c : list) {
            tmpChinaBankMap.put(c.getBusinessOrderType(), c);
        }
    }

    private void castVal2FuminBankConfig (String val, Map<String, FuminBankBusinessConfig> tmpChinaBankMap) {
        List<FuminBankBusinessConfig> list = JSONUtils.parse2List(val, FuminBankBusinessConfig.class);
        for(FuminBankBusinessConfig c : list) {
            tmpChinaBankMap.put(c.getBusinessOrderType(), c);
        }
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        //初始话配置
        initConfig();
        initFuminPayConfig();
        initProfitSharingAccountConfig();
        initFuminAccountConfig();
        Set set = new HashSet();
        set.add(ApolloConstants.BANK_BUSINESS_ORDER_CONFIG_NEW);
        set.add(ApolloConstants.BANK_FUMIN_PAY_CONFIG);
        set.add(ApolloConstants.PROFIT_SHARING_ACCOUNT_CONFIG);
        set.add(ApolloConstants.FUMIN_ACCOUNT_CONFIG);
        //动态监听配置变化
        Config config = ConfigService.getAppConfig();
        config.addChangeListener(new ConfigChangeListener() {
            @Override
            public void onChange(ConfigChangeEvent changeEvent) {
                initConfig();
                initFuminPayConfig();
                initFuminAccountConfig();
                log.info("ChinaBankAdapter#onChange change configs success chinaBankMap:{} fuminBankMap:{}, fuminBankPayConfigMap：{}, profitSharingAccountConfig：{}, accountList:{}"
                        ,JSONUtils.toJSON(chinaBankMap), JSONUtils.toJSON(fuminBankMap), JSONUtils.toJSON(fuminBankPayConfigMap), JSONUtils.toJSON(profitSharingAccountConfig), JSONUtils.toJSON(accountList));
            }
        }, set);
    }

}